// Copyright 2017 Proyectos y Sistemas de Mantenimiento SL (eProsima).
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// ------------------------------------------------------------------
// Modification history:
// feature: support agent between domain
// feature: Unified Transport Abstraction Layer Unified Transport Abstraction Layer
// feature: add fast heartbeat feature
// feature: destination order support by reception timestamp
// feature: QoS Profile Inheritance and Composition
// feature: simplify xml profile
// ------------------------------------------------------------------

#ifndef INCLUDE_ERTPS_XMLPARSER_XMLPARSER_H_
#define INCLUDE_ERTPS_XMLPARSER_XMLPARSER_H_

#include <transport/TransportDescriptorInterface.h>
#include <ertps/attributes/ParticipantAttributes.h>
#include <ertps/attributes/PublisherAttributes.h>
#include <ertps/attributes/SubscriberAttributes.h>
#include <xmlparser/XMLParserCommonPart.h>
#include <ertps/types/DynamicTypeBuilderPtr.h>
#include <ertps/types/DynamicTypeBuilder.h>
#include <ertps/attributes/LibrarySettingsAttributes.h>
#include <xmlparser/XMLTreePart.h>
#include <xmlparser/XMLParserPart.h>

#include <map>
#include <string>

namespace evbs {
namespace ertps {
namespace xmlparser {

using vbsutil::xmlparser::XMLP_ret;
using xmlString = vbsutil::xmlparser::xmlString;

typedef std::shared_ptr<vbs::transport::TransportDescriptorInterface> sp_transport_t;
typedef std::map<std::string, sp_transport_t> sp_transport_map_t;
typedef types::DynamicTypeBuilder* p_dynamictypebuilder_t;
typedef std::map<std::string, p_dynamictypebuilder_t> p_dynamictype_map_t;

/**
 * Class XMLParser, used to load XML data.
 * @ingroup XMLPARSER_MODULE
 */
class XMLParser {
 private:
    static std::set<std::string> agent_allowed_topic_;
    static std::mutex mutex_;

 public:
    /**
     * Load a XML file.
     * @param filename Name for the file to be loaded.
     * @param root Root node.
     * @return XMLP_ret::XML_OK on success, XMLP_ret::XML_ERROR in other case.
     */
    RTPS_DllAPI static XMLP_ret loadXML(const std::string& filename, vbsutil::xmlparser::up_base_node_t& root);

    /**
     * Load a XML data from buffer.
     * @param data XML data to load.
     * @param length Length of the XML data.
     * @param root Root node.
     * @return XMLP_ret::XML_OK on success, XMLP_ret::XML_ERROR in other case.
     */
    RTPS_DllAPI static XMLP_ret loadXML(const char* data, size_t length, vbsutil::xmlparser::up_base_node_t& root);

    /**
     * Load a XML node.
     * @param xmlDoc Node to be loaded.
     * @param root Root node.
     * @return XMLP_ret::XML_OK on success, XMLP_ret::XML_ERROR in other case.
     */
    RTPS_DllAPI static XMLP_ret loadXML(tinyxml2::XMLDocument& xmlDoc, vbsutil::xmlparser::up_base_node_t& root);

    /**
     * Load a XML node.
     * @param profiles Node to be loaded.
     * @param root Root node.
     * @return XMLP_ret::XML_OK on success, XMLP_ret::XML_ERROR in other case.
     */
    RTPS_DllAPI static XMLP_ret loadXMLProfiles(tinyxml2::XMLElement& profiles,
                                                vbsutil::xmlparser::up_base_node_t& root);

    /**
     * Load a XML node.
     * @param types Node to be loaded.
     * @return XMLP_ret::XML_OK on success, XMLP_ret::XML_ERROR in other case.
     */
    RTPS_DllAPI static XMLP_ret loadXMLDynamicTypes(tinyxml2::XMLElement& types);

    RTPS_DllAPI static std::set<std::string> getAgentAllowedTopics() {
        std::lock_guard<std::mutex> lock(mutex_);
        return agent_allowed_topic_;
    }

 protected:
    RTPS_DllAPI static XMLP_ret parseAgentConfig(tinyxml2::XMLElement* p_root);

    RTPS_DllAPI static XMLP_ret parseXML(tinyxml2::XMLDocument& xmlDoc, vbsutil::xmlparser::up_base_node_t& root);

    RTPS_DllAPI static XMLP_ret parseXMLProfiles(tinyxml2::XMLElement& profiles,
                                                 vbsutil::xmlparser::up_base_node_t& root);

    RTPS_DllAPI static XMLP_ret parseProfiles(tinyxml2::XMLElement* p_root);

    /**
     * Load a XML log node and parses it. It applies the configuration of the node directly.
     * @param p_root Node to be loaded.
     * @return XMLP_ret::XML_OK on success, XMLP_ret::XML_ERROR in other case.
     */
    RTPS_DllAPI static XMLP_ret parseLogConfig(tinyxml2::XMLElement* p_root);

    RTPS_DllAPI static XMLP_ret parseXMLLibrarySettings(tinyxml2::XMLElement* p_root);

    RTPS_DllAPI static XMLP_ret parseXMLTransportsProf(tinyxml2::XMLElement* p_root);

    RTPS_DllAPI static XMLP_ret parseXMLTransportData(tinyxml2::XMLElement* p_root);

    RTPS_DllAPI static XMLP_ret parseXMLCommonTransportData(tinyxml2::XMLElement* p_root, sp_transport_t p_transport);

    RTPS_DllAPI static XMLP_ret parse_tls_config(tinyxml2::XMLElement* p_root, sp_transport_t tcp_transport);

    /**
     * Load a XML consumer node and parses it. Adds the parsed consumer to Log directly.
     * @param consumer Node to be loaded.
     * @return XMLP_ret::XML_OK on success, XMLP_ret::XML_ERROR in other case.
     */
    RTPS_DllAPI static XMLP_ret parseXMLConsumer(tinyxml2::XMLElement& consumer);

    RTPS_DllAPI static XMLP_ret parseXMLDynamicTypes(tinyxml2::XMLElement& types);

    RTPS_DllAPI static XMLP_ret parseDynamicTypes(tinyxml2::XMLElement* p_root);

    RTPS_DllAPI static XMLP_ret parseXMLTypes(tinyxml2::XMLElement* p_root);

    RTPS_DllAPI static XMLP_ret parseXMLDynamicType(tinyxml2::XMLElement* p_root);

    RTPS_DllAPI static XMLP_ret parseXMLStructDynamicType(tinyxml2::XMLElement* p_root);

    RTPS_DllAPI static XMLP_ret parseXMLUnionDynamicType(tinyxml2::XMLElement* p_root);

    RTPS_DllAPI static XMLP_ret parseXMLEnumDynamicType(tinyxml2::XMLElement* p_root);

    RTPS_DllAPI static XMLP_ret parseXMLAliasDynamicType(tinyxml2::XMLElement* p_root);

    RTPS_DllAPI static XMLP_ret parseXMLBitsetDynamicType(tinyxml2::XMLElement* p_root);

    RTPS_DllAPI static XMLP_ret parseXMLBitmaskDynamicType(tinyxml2::XMLElement* p_root);

    RTPS_DllAPI static p_dynamictypebuilder_t parseXMLBitfieldDynamicType(tinyxml2::XMLElement* p_root,
                                                                          p_dynamictypebuilder_t p_dynamictype,
                                                                          vbs::common::types::MemberId mId,
                                                                          uint16_t& position);

    RTPS_DllAPI static XMLP_ret parseXMLBitvalueDynamicType(tinyxml2::XMLElement* p_root,
                                                            p_dynamictypebuilder_t p_dynamictype, uint16_t& position);

    RTPS_DllAPI static p_dynamictypebuilder_t parseXMLMemberDynamicType(tinyxml2::XMLElement* p_root,
                                                                        p_dynamictypebuilder_t p_dynamictype,
                                                                        vbs::common::types::MemberId mId);

    RTPS_DllAPI static p_dynamictypebuilder_t parseXMLMemberDynamicType(tinyxml2::XMLElement* p_root,
                                                                        p_dynamictypebuilder_t p_dynamictype,
                                                                        vbs::common::types::MemberId mId,
                                                                        const std::string& values);

    RTPS_DllAPI static XMLP_ret getXMLEnum(tinyxml2::XMLElement* elem, IntraprocessDeliveryType* e, uint8_t ident);
};

}  // namespace xmlparser
}  // namespace ertps
}  // namespace evbs

#endif  // INCLUDE_ERTPS_XMLPARSER_XMLPARSER_H_
